﻿/*
 * Tencent is pleased to support the open source community by making xLua available.
 * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
 * Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
 * http://opensource.org/licenses/MIT
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
*/

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using XLua;
using System;

namespace XLuaTest
{
    [LuaCallCSharp]
    public class LuaBehaviour : MonoBehaviour
    {
        public TextAsset luaScript; //lua脚本的文本文件
        public Injection[] injections;//要注入到lua的游戏物体,方便lua侧操作这些游戏对象

        internal static LuaEnv luaEnv = new LuaEnv(); //所有的LuaBehaviour脚本使用同一个luaEnv对象,所以静态了
        internal static float lastGCTime = 0;//垃圾回收计时,上一次的垃圾回收时间
        internal const float GCInterval = 1;//垃圾回收间隔 , 当前时间减去上次垃圾回收时间等于这个间隔就回收垃圾


        private Action luaAwake;//因为awake至执行1此,从lua导出这个方法的时候就执行了,所以没必要写在这里
        private Action luaStart;//用来映射lua侧的start方法
        private Action luaUpdate;//用来映射lua侧的update方法
        private Action luaOnDestroy;//用来映射lua侧的destroy方法
        //......还可以添加需要的方法,但是大部分类值包含这几个方法就可以了

        private LuaTable scriptEnv;//脚本环境

        void Awake()
        {
            scriptEnv = luaEnv.NewTable();//在lua侧创建一个表,等同于C#的一个组件

            // 为每个脚本设置一个独立的环境，可一定程度上防止脚本间全局变量、函数冲突
            //下面这四句话是给scriptEnv设置原表
            LuaTable meta = luaEnv.NewTable();
            meta.Set("__index", luaEnv.Global);
            scriptEnv.SetMetaTable(meta);
            meta.Dispose();
            //把this设置给scriptEnv表的self,在lua侧就可以通过self等效访问此MonoBehaviour中的成员
            scriptEnv.Set("self", this);

            //注入需要引用的游戏物体
            foreach (var injection in injections)
            {
                scriptEnv.Set(injection.name, injection.value);
            }

            //在此之前scriptEnv是一个空表,把lua脚本中定义的成员给了scriptEnv,没有研究过怎么实现的
            luaEnv.DoString(luaScript.text, "LuaTestScript", scriptEnv);

            scriptEnv.Get("awake",out luaAwake);
            scriptEnv.Get("start", out luaStart);
            scriptEnv.Get("update", out luaUpdate);
            scriptEnv.Get("ondestroy", out luaOnDestroy);
           
            luaAwake?.Invoke();//执行lua侧定义的awake
        }

        // Use this for initialization
        void Start()
        {
            luaStart?.Invoke(); //调用lua侧的start
        }

        // Update is called once per frame
        void Update()
        {
            luaUpdate?.Invoke();//调用lua侧的update
            if (Time.time - LuaBehaviour.lastGCTime > GCInterval)
            {
                luaEnv.Tick();
                LuaBehaviour.lastGCTime = Time.time;
            }
        }

        void OnDestroy()
        {
            luaOnDestroy?.Invoke();//调用lua侧的ondestroy
            luaOnDestroy = null;
            luaUpdate = null;
            luaStart = null;
            scriptEnv.Dispose();
            injections = null;
        }
    }
}


[System.Serializable]
public class Injection  //要注入到lua的游戏对象,也可以改写成其他的C#对象  甚至system.object
{
    public string name;
    public GameObject value;
}